using System;
using System.Collections.Generic;

using Multiplicity.Runtime.Serialization.Binary;

namespace Multiplicity.Reflection {

    [AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)]
    sealed class MetadataTableAttribute : Attribute {
        readonly MetadataTableType tableType;

        public MetadataTableAttribute(MetadataTableType tableType) {
            this.tableType = tableType;
        }
        public MetadataTableType TableType {
            get {
                return this.tableType;
            }
        }
    }

    sealed class MetadataTable<TRow> where TRow : MetadataRow, new() {

        readonly MetadataTableType tableType = MetadataTableType.Invalid;
        readonly uint count;
        readonly TRow[] rows;

        internal MetadataTable(MetadataStream stream) {

            MetadataTableAttribute[] atr = (MetadataTableAttribute[])typeof(TRow).GetCustomAttributes(typeof(MetadataTableAttribute), false);
            if (atr.Length != 0) {
                tableType = atr[0].TableType;

                this.count = stream.TableRowCount(tableType);
                this.rows = new TRow[count];

                for (int i = 0; i < count; i++) {
                    rows[i] = stream.ReadRecord<TRow>();
                }
            }
            else {
                this.rows = new TRow[0];
            }
        }

        public uint Count {
            get { return count; }
        }

        /// <param name="index">one-based row index</param>
        public TRow this[uint index] {
            get { return rows[index]; }
        }

        public MetadataTableType TableType {
            get { return tableType; }
        }

    }
    [BinaryRecord]
    abstract class MetadataRow {
        protected MetadataRow() {
        }
    }

    public enum MetadataTableType : uint {
        Module          = 0x00,
        TypeRef         = 0x01,
        TypeDef         = 0x02,
        Field           = 0x04,
        MethodDef       = 0x06,
        ParamDef        = 0x08,
        InterfaceImpl   = 0x09,
        MemberRef       = 0x0a,
        CustomAttribute = 0x0c,
        Permission      = 0x0e,
        Signature       = 0x11,
        Event           = 0x14,
        Property        = 0x17,
        ModuleRef       = 0x1a,
        TypeSpec        = 0x1b, 
        Assembly        = 0x20, 
        AssemblyRef     = 0x23,
        File            = 0x26,
        ExportedType    = 0x27,
        ManifestResource = 0x28,
        GenericParam    = 0x2a,
        MethodSpec      = 0x2b,
        GenericParamConstraint = 0x2c,

        Invalid = uint.MaxValue,

    }
}
